#include "stdafx.h"
#include <assert.h>
#include <math.h>

#ifndef NDEBUG
	#define DOUT( toprint ) printf( "\n# " toprint )        //!< Debug output, prints a plain text line preceded by #
	#define DPUT( toput , x ) printf( "\n# " toput , x )	//!< Debug put, a DOUT with a single variable inside
	#define DLN                                             //!< Debug line, doesn't exist in release ( with NDEBUG defined )
	#define DPUTCLOSURE	DOUT("=============================================================================");\
		DPUT("FILE: %s", __FILE__); \
		DPUT("COMPILATION DATE: %s", __DATE__); \
		DPUT("COMPILATION TIME: %s\n", __TIME__)//!< Put a closing statement, complete with datestamp and finename.
#else
	#define DOUT
	#define DPUT
	#define DLN if(0)
	#define DPUTCLOSURE
#endif

char * currCHAR = NULL;

int GetG3(char*);
int GetN();
int GetE();
int GetT();
int GetP();

int main(int argc, char **argv[])
{
	char input[] = "12000-6*(1000+3000)/3";
	int result = GetG3(input);
	DPUT("Result is %d", result);
	DPUTCLOSURE;
	return 0;
}

/*********************************************************************************/
/* @note - in_string isn't const because otherwise "conversion loses qualifiers" */
/*********************************************************************************/
int GetG3(char * in_string) 
{
	assert(("GetG3 received a non-NULL pointer to initialize with", in_string != NULL));

	currCHAR = in_string;
	int res = GetE();
	assert(("Syntax analysis finished successfully", *currCHAR == '\0'));

	return res;
}

int GetE() 
{
	int val = GetT();

	while (*currCHAR == '-' || *currCHAR == '+') {
		int oper = *currCHAR++,
			val2 = GetT();
		DPUT("OPERATOR GOT: %c", oper);
		val = (oper == '+' ? val + val2 : val - val2);
	}

	return val;
}

int GetT()
{
	int val = GetP();

	while (*currCHAR == '*' || *currCHAR == '/') {
		int oper = *currCHAR++,
			val2 = GetP();
		DPUT("OPERATOR GOT: %c", oper);
		val = (oper == '*' ? val * val2 : val / val2);
	}

	return val;
}

int GetN()
{
	int val = 0;
	while ('0' <= *currCHAR && *currCHAR <= '9') {
		DPUT("CHAR GOT: %c", *currCHAR);
		val = val * 10 + (*currCHAR) - '0';
		currCHAR++;
	}

	return val;
}

int GetP() 
{
	if (*currCHAR == '(') {
		currCHAR++;

		int val = GetE();

		assert(( "Closing bracket found after expression parsing",*currCHAR == ')' ));
		currCHAR++;

		return val;
	} else
		return GetN();
}

int GetV()
{
	int retchar = 0;
	if ( ('A' <= *currCHAR && *currCHAR <= 'Z') || 
		 ('a' <= *currCHAR && *currCHAR <= 'z') ) {
		retchar = *currCHAR;
		currCHAR++;
	}
	return retchar;
}